home *** CD-ROM | disk | FTP | other *** search
/ The X-Philes (2nd Revision) / The X-Philes Number 1 (1995).iso / xphiles / hp48hor2 / tasc8.c < prev    next >
C/C++ Source or Header  |  1993-02-18  |  9KB  |  315 lines

  1. /* tasc (version 3):  ASC-encoder/decoder for HP48 files
  2. Copyright 1992 by Jonathan T. Higa
  3. Credits:
  4. - ASC:  Bill Wickes (billw@hpcvdw.cv.hp.com).
  5. - Cyclic Redundancy Check:
  6. da Cruz, Frank.  _Kermit:  A File Transfer Protocol._
  7. Bedford, MA:  Digital Press, 1987.
  8. - Object structure:
  9. HP48 Tools Manual;
  10. "HP48SX Internals," by Derek S. Nickel.
  11. - Guidance:  Joe Horn (akcs.joehorn@hpcvbbs.cv.hp.com)
  12. - Original inspiration:
  13. miscellaneous asc2bin programs on seq.uncwil.edu
  14. */
  15.  
  16. #include <stdio.h>
  17. #include <string.h>
  18.  
  19. struct hexbuf {
  20.    unsigned long bits;
  21.    long nibs;
  22.    int bsize;
  23.    unsigned short crc;
  24. };
  25.  
  26. enum hpdatatype { HPBIN, HPASC, UNKNOWN = -1 };
  27.  
  28. int verbose = 1;
  29.  
  30. void pushhex(struct hexbuf *b, int h)
  31. /* Add a hex digit to the bit buffer. */
  32. {
  33.    b->bits |= (h & 0xfuL) << b->bsize;
  34.    b->bsize += 4;
  35. }
  36.  
  37. int pophex(struct hexbuf *b)
  38. /* Remove and return a hex digit from the bit buffer, and
  39.    include it in the CRC. */
  40. {
  41.    int h = b->bits & 0xf;
  42.    b->crc = (b->crc >> 4) ^ (((b->crc ^ h) & 0xf) * 0x1081);
  43.    b->nibs++;
  44.    b->bits >>= 4;
  45.    b->bsize -= 4;
  46.    return h;
  47. }
  48.  
  49. enum hpdatatype hptype(FILE *f)
  50. /* Determine the type of HP file by scanning the beginning of the file.
  51.    If the type is known, put the file pointer at the start of data. */
  52. {
  53.    char c;
  54.    if (fscanf(f, "HPHP48-%c", &c) == 1)
  55.       return HPBIN;
  56.    else
  57.       for (; ; )
  58.           switch (fscanf(f, "%*[%]HP:%*[^;]%c", &c)) {
  59.           case 1:
  60.              while (fscanf(f, " @%c", &c) == 1) {
  61.                 if (c != '\n') {
  62.                    fscanf(f, "%*[^\n]");
  63.                    fscanf(f, "%*1[\n]");
  64.                 }
  65.              }
  66.              return fscanf(f, "%c", &c) == 1 && c == '"' ? HPASC : UNKNOWN;
  67.           case 0:
  68.              fscanf(f, "%*[^\n]");
  69.              fscanf(f, "%*1[\n]");
  70.              break;
  71.           case EOF:
  72.              return UNKNOWN;
  73.           }
  74. }
  75.  
  76. char *newext(char *new, const char *old, const char *ext)
  77. /* Create a new filename from the old filename and extension. */
  78. {
  79.    char *p = strrchr(strcpy(new, old), ext[0]);
  80.    if (p) strcpy(p, ext);
  81.    else strcat(new, ext);
  82.    if (verbose) fprintf(stderr, "tasc: inventing filename \"%s\"\n", new);
  83.    return new;
  84. }
  85.  
  86. int asctobin(FILE *fasc, FILE *fbin)
  87. {
  88.    struct hexbuf hb = {0, 0, 0, 0};
  89.    int d;
  90.  
  91.    /* write header into binary file */
  92.    fputs("HPHP48-E", fbin);
  93.  
  94.    /* translate data */
  95.    while (fscanf(fasc, "%1x", &d) == 1) {
  96.       pushhex(&hb, d);
  97.       if (hb.bsize >= 24) {
  98.           d = pophex(&hb);
  99.           d |= pophex(&hb) << 4;
  100.           putc(d, fbin);
  101.       }
  102.    }
  103.    if (hb.bsize > 16) {
  104.       d = pophex(&hb);
  105.       putc(d, fbin);
  106.    }
  107.  
  108.    /* check CRC */
  109.    if (hb.crc != hb.bits || hb.bsize != 16) {
  110.       fprintf(stderr, "tasc: ASC->bin: CRC is incorrect\n");
  111.       return 1;
  112.    }
  113.    if (verbose)
  114.       fprintf(stderr, "tasc: ASC->bin: BYTES: #%hXh %ld%s\n",
  115.               hb.crc, hb.nibs/2, hb.nibs & 1 ? ".5" : "");
  116.    return 0;
  117. }
  118.  
  119. int bintoasc(FILE *fbin, FILE *fasc)
  120. {
  121.    struct hexbuf hb = {0, 0, 0, 0};
  122.    unsigned long fldlen = 0;
  123.    enum { SIZE, ASCIC, ASCIX, DIR, ANY = -1 } fldnxt = ANY;
  124.    int c, width = 0;
  125.  
  126.    /* write header into ASC file */
  127.    fprintf(fasc, "%%%%HP: T(1);\n\"");
  128.  
  129.    /* parse binary */
  130.    while ((c = getc(fbin)) != EOF) {
  131.       pushhex(&hb, c);
  132.       pushhex(&hb, c >> 4);
  133.       if (!fldlen) /* done with previous field */
  134.           switch (fldnxt) { /* now for the current field */
  135.           case SIZE:
  136.              if (hb.bsize >= 20) {
  137.                 /* this object's length is known by the size field */
  138.                 fldlen = hb.bits & 0xfffff;
  139.                 fldnxt = ANY;
  140.              }
  141.              break;
  142.           case ASCIC:
  143.              if (hb.bsize >= 8) {
  144.                 /* ASCII-char identifier */
  145.                 fldlen = 2 + 2 * (hb.bits & 0xff);
  146.                 fldnxt = ANY;
  147.              }
  148.              break;
  149.           case ASCIX:
  150.              if (hb.bsize >= 8) {
  151.                 /* ASCII-extended identifier */
  152.                 fldlen = 4 + 2 * (hb.bits & 0xff);
  153.                 fldnxt = ANY;
  154.              }
  155.              break;
  156.           case DIR:
  157.              if (hb.bsize >= 20) {
  158.                 /* first object pointer in a directory, to an ASCIX name */
  159.                 fldlen = hb.bits & 0xfffff;
  160.                 fldnxt = ASCIX;
  161.              }
  162.              break;
  163.           default:
  164.              if (hb.bsize >= 20) {
  165.                 unsigned long pro = hb.bits & 0xfffff;
  166.                 fldlen = 5; /* the prolog field is 5 nibbles long */
  167.                 if (pro == 0x29e8uL || pro == 0x2a0auL || pro == 0x2a2cuL
  168.                     || pro == 0x2a4euL || pro == 0x2b1euL || pro == 0x2b40uL
  169.                     || pro == 0x2b62uL || pro == 0x2b88uL || pro == 0x2dccuL)
  170.                    fldnxt = SIZE; /* expect a size field */
  171.                 else if (pro == 0x2e48uL || pro == 0x2e6duL || pro == 0x2afcuL)
  172.                    fldnxt = ASCIC; /* expect an ASCIC object */
  173.                 else if (pro == 0x2a96uL) {
  174.                    /* expect the directory pointer after the first 8 nibbles */
  175.                    fldlen = 8;
  176.                    fldnxt = DIR;
  177.                 }
  178.                 else if (pro == 0x2911uL) fldlen = 10; /* is system binary */
  179.                 else if (pro == 0x2933uL) fldlen = 21; /* is real */
  180.                 else if (pro == 0x2955uL) fldlen = 26; /* is long real */
  181.                 else if (pro == 0x2977uL) fldlen = 37; /* is complex */
  182.                 else if (pro == 0x299duL) fldlen = 47; /* is long complex */
  183.                 else if (pro == 0x29bfuL) fldlen = 7; /* is char */
  184.                 else if (pro == 0x2e92uL) fldlen = 11; /* is XLIB name */
  185.              }
  186.              break;
  187.           }
  188.       
  189.       /* write out the current field */
  190.       while (fldlen && hb.bsize) {
  191.           c = pophex(&hb);
  192.           if (width == 64) {
  193.              putc('\n', fasc);
  194.              width = 0;
  195.           }
  196.           fprintf(fasc, "%X", c);
  197.           width++;
  198.           fldlen--;
  199.       }
  200.    }
  201.    if (hb.bits) {
  202.       fprintf(stderr, "tasc: bin->ASC: end of last object not found\n");
  203.       return 1;
  204.    }
  205.  
  206.    /* append CRC */
  207.    if (verbose)
  208.       fprintf(stderr, "tasc: bin->ASC: BYTES: #%hXh %ld%s\n",
  209.               hb.crc, hb.nibs / 2, hb.nibs & 1 ? ".5" : "");
  210.    hb.bits = hb.crc;
  211.    hb.bsize = 16;
  212.    while (hb.bsize) {
  213.       if (width == 64) {
  214.           putc('\n', fasc);
  215.           width = 0;
  216.       }
  217.       fprintf(fasc, "%X", pophex(&hb));
  218.       width++;
  219.    }
  220.    fprintf(fasc, "\"\n");
  221.    return 0;
  222. }
  223.  
  224. int main(int argc, char **argv)
  225. {
  226.    const char *STDIO = "-";
  227.    enum hpdatatype coding = UNKNOWN;
  228.    int i = 1;
  229.    char *iname, *oname, temp[256];
  230.    if (argc > i && argv[i][0] == '-') {
  231.       switch (argv[i][1]) {
  232.       case 'd':
  233.           coding = HPASC;
  234.           i++;
  235.           break;
  236.       case 'e':
  237.           coding = HPBIN;
  238.           i++;
  239.           break;
  240.       case 'q':
  241.          verbose = 0;
  242.          i++;
  243.          break;
  244.       }
  245.    }
  246.    argc -= i;
  247.    if (argc < 1 || argc > 2) {
  248.       fprintf(stderr, "Use: %s [opt ...] source [target]\n"
  249.               "opt\taction\n"
  250.               " -d\tForce ASC->bin (ASC decode)\n"
  251.               " -e\tForce bin->ASC (ASC encode)\n"
  252.               " -q\tSuppress non-error messages (quiet)\n"
  253.               "The filename \"-\" represents the terminal.\n",
  254.               argv[0]);
  255.       return 1;
  256.    }
  257.    iname = argv[i];
  258.    if (strcmp(iname, STDIO)) {
  259.       if (!freopen(iname, "rb", stdin)) {
  260.           fprintf(stderr, "tasc: ");
  261.           perror(iname);
  262.           return 1;
  263.       }
  264.    } else if (argc == 1) {
  265.       fprintf(stderr, "tasc: cannot invent output filename for stdin\n");
  266.       return 1;
  267.    }
  268.    switch (hptype(stdin)) {
  269.    case HPASC:
  270.       if (coding == HPBIN) {
  271.           fprintf(stderr, "tasc: ASC->bin mode was disallowed\n");
  272.           return 1;
  273.       }
  274.       if (verbose) fprintf(stderr, "tasc: entering ASC->bin mode\n");
  275.       oname = argc == 1 ? newext(temp, iname, ".bin") : argv[i+1];
  276.       if (strcmp(oname, STDIO) && !freopen(oname, "wb", stdout)) {
  277.           fprintf(stderr, "tasc: ");
  278.           perror(oname);
  279.           return 1;
  280.       }
  281.       if (asctobin(stdin, stdout))
  282.           return 1;
  283.       break;
  284.    case HPBIN:
  285.       if (coding == HPASC) {
  286.           fprintf(stderr, "tasc: bin->ASC mode was disallowed\n");
  287.           return 1;
  288.       }
  289.       if (verbose) fprintf(stderr, "tasc: entering bin->ASC mode\n");
  290.       oname = argc == 1 ? newext(temp, iname, ".asc") : argv[i+1];
  291.       if (strcmp(oname, STDIO) && !freopen(oname, "w", stdout)) {
  292.           fprintf(stderr, "tasc: ");
  293.           perror(oname);
  294.           return 1;
  295.       }
  296.       if (bintoasc(stdin, stdout))
  297.           return 1;
  298.       break;
  299.    default:
  300.       fprintf(stderr, "tasc: unknown input type\n");
  301.       return 1;
  302.    }
  303.    if (fclose(stdin)) {
  304.       fprintf(stderr, "tasc: ");
  305.       perror(iname);
  306.       return 1;
  307.    }
  308.    if (fclose(stdout)) {
  309.       fprintf(stderr, "tasc: ");
  310.       perror(oname);
  311.       return 1;
  312.    }
  313.    return 0;
  314. }
  315.